﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace Pavilion.GameTools
{
    public class SpeedIncrementation
    {
        public event Action<SpeedIncrementation> Complete;
        public Vector2 IncrementAmount { get { return incrementAmount; } set { SetIncrementAmount(value); } }
        public Vector2 Limit { get; set; }

        private GameItem gameItem;
        private PhysicalTypeTool physicalTool;
        private AnimationTool animationTool;
        private Vector2 incrementAmount;
        private Predicate<float> checkXLimitPredicate, checkYLimitPredicate;
        private Logger logger;
        private bool isRunning;

        public SpeedIncrementation(GameItem gameItem)
        {
            this.gameItem = gameItem;
            this.logger = Logger.GetLogger(gameItem.Name);

            physicalTool = gameItem.ObtainTool<PhysicalTypeTool>();
            animationTool = gameItem.ObtainTool<AnimationTool>();
        }

        public void StartIncrementing()
        {
            if (isRunning) return;

            logger.WriteLine("StartIncrementing - Speed=" + physicalTool.PolygonData.SpeedX + ", " + physicalTool.PolygonData.SpeedY);
            isRunning = true;
            gameItem.UpdateLogic += new Action<GameTime>(GameItem_UpdateLogic);
            animationTool.AnimationNodeUnloaded += new Action<NodeBase>(AnimationTool_AnimationNodeUnloaded);
        }

        public void StopIncrementing()
        {
            if (!isRunning) return;

            logger.WriteLine("StopIncrementing - Speed=" + physicalTool.PolygonData.SpeedX + ", " + physicalTool.PolygonData.SpeedY);

            isRunning = false;
            gameItem.UpdateLogic -= new Action<GameTime>(GameItem_UpdateLogic);
            animationTool.AnimationNodeUnloaded -= new Action<NodeBase>(AnimationTool_AnimationNodeUnloaded);

            OnComplete();
        }

        private void Increment()
        {
            if (checkXLimitPredicate.Invoke(physicalTool.PolygonData.SpeedX))
            {
                physicalTool.PolygonData.SpeedX += IncrementAmount.X;

                if (isRunning && !checkXLimitPredicate.Invoke(physicalTool.PolygonData.SpeedX))
                {
                    logger.WriteLine("About to Set SpeedX to LimitX. SpeedX=" + physicalTool.PolygonData.SpeedX + ", LimitX= " + Limit.X);
                    physicalTool.PolygonData.SpeedX = Limit.X;
                }
            }

            if (checkYLimitPredicate.Invoke(physicalTool.PolygonData.SpeedY))
            {
                physicalTool.PolygonData.SpeedY += IncrementAmount.Y;

                if (isRunning && !checkYLimitPredicate.Invoke(physicalTool.PolygonData.SpeedY))
                {
                    logger.WriteLine("About to Set SpeedY to LimitY. SpeedY=" + physicalTool.PolygonData.SpeedY + ", LimitY= " + Limit.Y);
                    physicalTool.PolygonData.SpeedY = Limit.Y;
                }
            }
        }

        private void SetIncrementAmount(Vector2 value)
        {
            this.incrementAmount = value;

            if (IncrementAmount.X < 0)
                checkXLimitPredicate = (speed) => speed > Limit.X;
            else if (IncrementAmount.X > 0)
                checkXLimitPredicate = (speed) => speed < Limit.X;
            else
                checkXLimitPredicate = (speed) => false;

            if (IncrementAmount.Y < 0)
                checkYLimitPredicate = (speed) => speed > Limit.Y;
            else if (IncrementAmount.Y > 0)
                checkYLimitPredicate = (speed) => speed < Limit.Y;
            else
                checkYLimitPredicate = (speed) => false;
        }

        private void OnComplete()
        {
            if (Complete != null)
                Complete(this);
        }

        private void GameItem_UpdateLogic(GameTime gameTime)
        {
            Increment();
        }

        private void AnimationTool_AnimationNodeUnloaded(NodeBase nodeBase)
        {
            StopIncrementing();
        }
    }
}
